﻿#pragma once

namespace CAGD
{

/**
 * @brief 容器类.
 *
 */
template <typename UnnamedType> struct container
{
  private:
    /**
     * @brief std::declval<UnnamedType>() 获得一个 UnnamedType 类型的对象，如果 UnnamedType
     * 是可调用的对象，则匹配此模板函数，执行 UnnamedType()( std::declval<Param>() ).
     * @return
     * @param
     * @see
     */
    template <typename Param>
    constexpr auto testValidity(int) -> decltype(std::declval<UnnamedType>()(std::declval<Param>()), std::true_type())
    {
        return std::true_type();
    }

    /**
     * @brief 用于接收 UnnamedType 不是可调用对象的情况.
     * @return
     * @param
     * @see
     */
    template <typename Param> constexpr std::false_type testValidity(...)
    {
        return std::false_type();
    }

  public:
    /**
     * @brief 重载使得 container 成为可调用对象。传入的 Param 是一个参数，作为 UnnamedType 调用的参数.
     * @return
     * @param p
     * @see
     */
    template <typename Param> constexpr auto operator()(const Param &p)
    {
        // 返回类型为 std::true_type 或 std::false_type
        return testValidity<Param>(int());
    }
};

/**
 * @brief is_valid 模板，传入一个 UnnamedType 类型，返回 container 是一个可调用对象.
 * @return
 * @param t
 * @see
 */
template <typename UnnamedType> constexpr auto is_valid(const UnnamedType &t)
{
    return container<UnnamedType>();
}

} // namespace CAGD
